home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: SoundConverter.c
- //
- // Contains: Sound format conversion sample code.
- //
- // Written by: Bob Aron
- // Revised by: Tim Monroe
- //
- // Copyright: © 1999 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <3> 07/07/99 rtm final tweaks
- // <2> 07/02/99 rtm fixed problem causing crashes on Windows
- // <1> 07/01/99 rtm first file from Bob Aron; conversion to personal coding style
- //
- // This is a simple application that demonstrates how to convert some uncompressed audio into any compression
- // format supported by QuickTime 4.0 and Sound Manager 3.4. There are two routines of interest in this file:
- // SndConv_ConvertSomeUncompressedAudio and SndConv_CreateSoundMovie.
- //
- // SndConv_ConvertSomeUncompressedAudio creates a 16-bit, mono, 44.1 kHz sine wave to use as source audio data
- // and then converts it to whatever format is desired. The output format is hard-coded at the beginning of the function
- // SndConv_DriveAudioConversion. SndConv_ConvertSomeUncompressedAudio places the converted data into a handle and then
- // calls SndConv_CreateSoundMovie to add the data to a newly-created movie.
- //
- //////////
-
- #include "SoundConverter.h"
-
-
- //////////
- //
- // SndConv_DriveAudioConversion
- // Create some sound data and compress it into a file.
- //
- //////////
-
- void SndConv_DriveAudioConversion (void)
- {
- Handle mySourceHandle,
- myDestHandle;
- Handle myDestCompParamsHandle = NULL;
- SoundComponentData mySourceInfo,
- myDestInfo;
- unsigned long mySourceTotalFrames,
- myDestTotalFrames;
- short myResRefNum = -1;
- CompressionInfo myDestCompressionInfo;
- Movie myMovie = NULL;
- StandardFileReply myReply;
- long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
- StringPtr myPrompt = QTUtils_ConvertCToPascalString(kSaveSoundPrompt);
- StringPtr myFileName = QTUtils_ConvertCToPascalString(kSaveSoundFileName);
- OSErr myErr = noErr;
-
- //////////
- //
- // allocate handles to hold the uncompressed (source) and compressed (destination) sound data
- //
- //////////
-
- mySourceHandle = NewHandleClear(0);
- myDestHandle = NewHandleClear(0);
-
- if ((mySourceHandle == NULL) || (myDestHandle == NULL))
- goto Bail;
-
- // create some uncompressed, 16-bit, mono, 44.1 kHz sound data; also, fill in the mySourceInfo structure
- // and return the total number of frames, which we'll use later
- myErr = SndConv_UncompressedSineWaveToHandle(mySourceHandle, &mySourceInfo, &mySourceTotalFrames);
- FailIf(myErr != noErr, Bail);
-
- //////////
- //
- // convert the source data
- //
- //////////
-
- // fill in the myDestInfo fields with the data format that you want to convert to
- myDestInfo.flags |= kNoRealtimeProcessing; // perform in non-real time for best quality (this can also be set to zero)
- myDestInfo.format = k16BitBigEndianFormat; // data format
- myDestInfo.numChannels = 1; // number of channels (1 for mono, 2 for stereo)
- myDestInfo.sampleSize = 16; // sample size (may be left at 16 for all formats except k8BitOffsetBinaryFormat)
- myDestInfo.sampleRate = rate44khz; // sample rate
- myDestInfo.sampleCount = 0; // leave set to 0
- myDestInfo.buffer = NULL; // leave set to NULL
- myDestInfo.reserved = 0; // leave set to 0
-
- // convert the source data
- myErr = SndConv_ConvertSomeUncompressedAudio( mySourceHandle,
- mySourceInfo,
- mySourceTotalFrames,
- myDestHandle,
- myDestInfo,
- &myDestTotalFrames,
- &myDestCompressionInfo,
- &myDestCompParamsHandle);
- FailIf(myErr != noErr, Bail);
-
- //////////
- //
- // create a new movie to hold the converted sound data
- //
- //////////
-
- // elicit a location from the user
- StandardPutFile(myPrompt, myFileName, &myReply);
- if (!myReply.sfGood)
- goto Bail;
-
- if (myReply.sfReplacing) {
- myErr = FSpDelete(&myReply.sfFile);
- if (myErr != noErr)
- goto Bail;
- }
-
- myErr = CreateMovieFile(&myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, myFlags, &myResRefNum, &myMovie);
- FailIf(myErr != noErr, Bail);
-
- // put the newly-converted data into the movie
- myErr = SndConv_CreateSoundMovie( myDestHandle,
- myResRefNum,
- myMovie,
- myDestInfo,
- &myDestCompParamsHandle,
- myDestCompressionInfo,
- myDestTotalFrames);
- FailIf(myErr != noErr, Bail);
-
- Bail:
-
- free(myPrompt);
- free(myFileName);
-
- if (myMovie != 0)
- DisposeMovie(myMovie);
-
- if (myResRefNum != -1)
- CloseMovieFile(myResRefNum);
-
- if (myDestHandle != NULL)
- DisposeHandle(myDestHandle);
-
- if (mySourceHandle != NULL)
- DisposeHandle(mySourceHandle);
-
- if (myDestCompParamsHandle != NULL)
- DisposeHandle(myDestCompParamsHandle);
-
- return;
- }
-
-
- //////////
- //
- // SndConv_ConvertSomeUncompressedAudio
- // Convert the specified sound data.
- //
- // This routine expects uncompressed, 16-bit mono data as source data.
- //
- //////////
-
-
- OSErr SndConv_ConvertSomeUncompressedAudio ( Handle theSourceHandle,
- SoundComponentData theSourceInfo,
- unsigned long theSourceTotalFrames,
- Handle theDestHandle,
- SoundComponentData theDestInfo,
- unsigned long *theDestFramesMoved,
- CompressionInfo *theDestCompInfo,
- Handle *theDestCompParams)
- {
- SoundConverter myConverter;
- Handle myDestCompParamsHandle = NULL;
- unsigned long myNumFramesLeft,
- mySourceFrames,
- myDestFrames,
- mySourceBytes,
- myDestBytes,
- myDataOffset = 0;
- Ptr myDestPtr = NULL;
- UInt16 hasOptionsDialog = 0;
- short mySourceBytesPerFrame = 2; // 16-bit mono uncompressed data is 2 bytes per frame
- OSErr myErr = noErr;
-
- //////////
- //
- // open a sound converter
- //
- //////////
-
- myErr = SoundConverterOpen(&theSourceInfo, &theDestInfo, &myConverter);
- if (myErr != noErr)
- goto Bail;
-
- // see if the destination format has an options dialog and open if it does
- myErr = SoundConverterGetInfo(myConverter, siOptionsDialog, &hasOptionsDialog);
- if ((myErr == noErr) && hasOptionsDialog) {
- myErr = SoundConverterSetInfo(myConverter, siOptionsDialog, NULL);
- FailIf(myErr != noErr, Bail);
- }
-
- // ignore this error, since some codecs don't use this selector (makes QDesign work)
- myErr = SoundConverterSetInfo(myConverter, siCompressionChannels, &theDestInfo.numChannels);
-
- //////////
- //
- // get the sound converter-specific settings.
- //
- //////////
-
- // Not all sound converters have custom settings; in this case myDestCompParamsHandle will be unchanged.
- // we need to return these settings to the caller, as they are required by the decompressor to be able
- // to decompress the compressed audio. If this audio is stored in a QuickTime movie, these parameters
- // will be stored in a SoundDescriptionExtension of type siDecompressionParams.
- myErr = SoundConverterGetInfo(myConverter, siCompressionParams, &myDestCompParamsHandle);
-
- // if any compression params were passed back, send it to the sound converter now
- if (myErr == noErr) {
- HLockHi(myDestCompParamsHandle);
- myErr = SoundConverterSetInfo(myConverter, siCompressionParams, *myDestCompParamsHandle);
- HUnlock(myDestCompParamsHandle);
- FailIf(myErr != noErr, Bail);
- } else {
- // no audio atom list to deal with, so set to NULL
- myDestCompParamsHandle = NULL;
- }
-
- // get sound converter buffer size info
- myErr = SoundConverterGetBufferSizes(myConverter, kMaxBufferSize, &mySourceFrames, &mySourceBytes, &myDestBytes);
- FailIf(myErr != noErr, Bail);
-
- // create destination data buffer
- myDestPtr = NewPtrClear(myDestBytes);
- myErr = MemError();
- FailIf(myErr != noErr, Bail);
-
- //////////
- //
- // convert the sound to the desired output format
- //
- //////////
-
- myErr = SoundConverterBeginConversion(myConverter);
- FailIf(myErr != noErr, Bail);
-
- // get info about destination compression
- // We need to return this information to the caller as they are required
- // in order to put this compressed audio into a QuickTime movie. This information
- // will go into the Version 1 Sound Description Handle.
-
- myErr = SoundConverterGetInfo(myConverter, siCompressionFactor, theDestCompInfo);
- if (myErr != noErr) {
- myErr = GetCompressionInfo(fixedCompression, theDestInfo.format, theDestInfo.numChannels, theDestInfo.sampleSize, theDestCompInfo);
- FailIf(myErr != noErr, Bail);
- }
-
- // myBytesPerFrame is not filled in by GetInfo, so we set it here
- theDestCompInfo->bytesPerFrame = theDestCompInfo->bytesPerPacket * theDestInfo.numChannels;
-
- // initialize destination total frame count to zero
- *theDestFramesMoved = 0;
-
- myNumFramesLeft = theSourceTotalFrames;
- HLockHi(theSourceHandle);
-
- // loop through buffers of size mySourceFrames
- while (myNumFramesLeft > 0) {
- // if there are fewer frames remaining than our source buffer size,
- // we're near the end of our data, so get what's remaining
- if (myNumFramesLeft < mySourceFrames)
- mySourceFrames = myNumFramesLeft;
-
- myErr = SoundConverterConvertBuffer(myConverter, *theSourceHandle + myDataOffset, mySourceFrames, myDestPtr, &myDestFrames, &myDestBytes);
- FailIf(myErr != noErr, Bail);
-
- // place the converted data into a handle
- myErr = PtrAndHand(myDestPtr, theDestHandle, myDestBytes);
- FailIf(myErr != noErr, Bail);
-
- // move offset to appropriate place in source data
- myDataOffset += mySourceFrames * mySourceBytesPerFrame;
-
- // keep track of total frames returned by converter
- *theDestFramesMoved += myDestFrames;
-
- myNumFramesLeft -= mySourceFrames;
- }
-
- // end the conversion, and see if we get back a few more bytes of data
- myErr = SoundConverterEndConversion(myConverter, myDestPtr, &myDestFrames, &myDestBytes);
- FailIf(myErr != noErr, Bail);
-
- HUnlock(theSourceHandle);
-
- // place any leftover converted data into the handle
- myErr = PtrAndHand(myDestPtr, theDestHandle, myDestBytes);
- FailIf(myErr != noErr, Bail);
-
- *theDestFramesMoved += myDestFrames;
-
- Bail:
-
- *theDestCompParams = myDestCompParamsHandle;
-
- if (myDestPtr != NULL)
- DisposePtr(myDestPtr);
-
- if (myConverter != NULL)
- SoundConverterClose(myConverter);
-
- return(myErr);
- }
-
-
- //////////
- //
- // SndConv_CreateSoundMovie
- // Create a sound movie from the specified handle of audio data.
- //
- //////////
-
- OSErr SndConv_CreateSoundMovie ( Handle theDestAudioData,
- short theMovieRefNum,
- Movie theMovie,
- SoundComponentData theDestInfo,
- Handle *theDestCompParams,
- CompressionInfo theDestCompInfo,
- unsigned long theDestFrameCount)
- {
- Track myTrack = NULL;
- Media myMedia = NULL;
- TimeScale myTimeScale;
- SoundDescriptionV1Handle mySampleDesc = NULL;
- unsigned long myLengthInSamples;
- OSErr myErr = noErr;
-
- //////////
- //
- // create the movie track and media
- //
- //////////
-
- myTrack = NewMovieTrack(theMovie, 0, 0, kFullVolume);
- myErr = GetMoviesError();
- FailIf(myErr != noErr, Bail);
-
- myTimeScale = (theDestInfo.sampleRate >> 16);
-
- // set new track to be a sound track
- myMedia = NewTrackMedia(myTrack, SoundMediaType, myTimeScale, NULL, 0);
- myErr = GetMoviesError();
- FailIf(myErr != noErr, Bail);
-
- // start a media editing session
- myErr = BeginMediaEdits(myMedia);
- FailIf(myErr != noErr, Bail);
-
- //////////
- //
- // create a sound sample description
- //
- //////////
-
- // use the SoundDescription format 1 because it adds fields for data size information
- // and is required by AddSoundDescriptionExtension if an extension is required for the compression format
- mySampleDesc = (SoundDescriptionV1Handle)NewHandleClear(sizeof(SoundDescriptionV1));
- myErr = MemError();
- FailIf(myErr != noErr, Bail);
-
- // fill in the fields of the sample description
- (*mySampleDesc)->desc.descSize = sizeof(SoundDescriptionV1);
- (*mySampleDesc)->desc.dataFormat = theDestInfo.format;
- (*mySampleDesc)->desc.resvd1 = 0;
- (*mySampleDesc)->desc.resvd2 = 0;
- (*mySampleDesc)->desc.dataRefIndex = 1;
- (*mySampleDesc)->desc.version = 1;
- (*mySampleDesc)->desc.revlevel = 0;
- (*mySampleDesc)->desc.vendor = 0;
- (*mySampleDesc)->desc.numChannels = theDestInfo.numChannels;
- (*mySampleDesc)->desc.sampleSize = theDestInfo.sampleSize;
- (*mySampleDesc)->desc.compressionID = 0;
- (*mySampleDesc)->desc.packetSize = 0;
- (*mySampleDesc)->desc.sampleRate = theDestInfo.sampleRate;
- (*mySampleDesc)->samplesPerPacket = theDestCompInfo.samplesPerPacket;
- (*mySampleDesc)->bytesPerPacket = theDestCompInfo.bytesPerPacket;
- (*mySampleDesc)->bytesPerFrame = theDestCompInfo.bytesPerFrame;
- (*mySampleDesc)->bytesPerSample = theDestCompInfo.bytesPerSample;
-
- // not all compression formats have compression params, so we only need to add a
- // sound description extension for those that do
- if (*theDestCompParams != NULL)
- AddSoundDescriptionExtension((SoundDescriptionHandle)mySampleDesc, *theDestCompParams, siDecompressionParams);
-
- //////////
- //
- // add samples to the media
- //
- //////////
-
- myLengthInSamples = theDestFrameCount * theDestCompInfo.samplesPerPacket;
- myErr = AddMediaSample( myMedia,
- theDestAudioData,
- 0,
- theDestFrameCount * theDestCompInfo.bytesPerFrame,
- 1,
- (SampleDescriptionHandle)mySampleDesc,
- myLengthInSamples,
- 0,
- NULL);
- FailIf(myErr != noErr, Bail);
-
-
- myErr = EndMediaEdits(myMedia);
- FailIf(myErr != noErr, Bail);
-
- //////////
- //
- // add the media to the track
- //
- //////////
-
- myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), FixRatio(1, 1));
- FailIf(myErr != noErr, Bail);
-
- myErr = AddMovieResource(theMovie, theMovieRefNum, NULL, NULL);
- FailIf(myErr != noErr, Bail);
-
- Bail:
- if (mySampleDesc != NULL)
- DisposeHandle((Handle)mySampleDesc);
-
- return(myErr);
- }
-
-
- //////////
- //
- // SndConv_UncompressedSineWaveToHandle
- // Create some 16-bit, monophonic, 44.1kHz data and stick it into a handle.
- //
- //////////
-
- OSErr SndConv_UncompressedSineWaveToHandle (Handle theData, SoundComponentData *theCompInfo, unsigned long *theTotalFrames)
- {
- long myIndex, myByteCounter;
- double_t mySinResult, myRate;
- long myPlotMe;
- float myPi = 3.14159;
- Byte *myBufferPtr = NULL;
- Byte *myStartOfBufferPtr = NULL;
- unsigned long myBytesCount = 0;
- long myFramesInBuffer = 10240;
- long myHz = kConcertA,
- mySeconds = 3;
- short myBytesPerFrame;
- OSErr myErr = noErr;
-
- *theTotalFrames = 0;
-
- theCompInfo->flags = 0;
- theCompInfo->format = k16BitBigEndianFormat;
- theCompInfo->numChannels = 1;
- theCompInfo->sampleSize = 16;
- theCompInfo->sampleRate = rate44khz;
- theCompInfo->sampleCount = mySeconds * (theCompInfo->sampleRate >> 16);
- theCompInfo->buffer = NULL;
- theCompInfo->reserved = 0;
-
- myBytesPerFrame = theCompInfo->sampleSize / 8;
-
- myBufferPtr = (Byte *)NewPtrClear(myFramesInBuffer * myBytesPerFrame);
- FailWithAction(myBufferPtr == NULL, myErr = memFullErr, Bail);
-
- myStartOfBufferPtr = myBufferPtr;
-
- myRate = theCompInfo->sampleRate / 65536.0;
-
- //////////
- // 2 π hz
- // (sin(i * ------)) * samplesize
- // rate
- //////////
-
- for (myIndex = 0; myIndex < theCompInfo->sampleCount; myIndex++) {
- mySinResult = sin(myIndex * ((2 * myPi * myHz) / myRate));
- myPlotMe = mySinResult * ((1 << (theCompInfo->sampleSize - 1)) - 1);
-
- for (myByteCounter = 1; myByteCounter <= (theCompInfo->sampleSize / 8); myByteCounter++, myBytesCount++, myBufferPtr++) {
- *myBufferPtr = myPlotMe >> (theCompInfo->sampleSize - (myByteCounter * 8));
- }
-
- if (myBytesCount == myFramesInBuffer * myBytesPerFrame) {
- myErr = PtrAndHand(myStartOfBufferPtr, theData, myBytesCount);
- FailIf(myErr != noErr, Bail);
-
- *theTotalFrames += myBytesCount / myBytesPerFrame;
- myBytesCount = 0; // reset bytes count
- myBufferPtr = myStartOfBufferPtr; // reset myBufferPtr
- }
- }
-
- myErr = PtrAndHand(myStartOfBufferPtr, theData, myBytesCount);
- FailIf(myErr != noErr, Bail);
-
- *theTotalFrames += myBytesCount / myBytesPerFrame;
-
- Bail:
- if (myBufferPtr != NULL)
- DisposePtr((Ptr)myBufferPtr);
-
- return(myErr);
- }
-
-
-